package com.querie.model;

import java.util.HashMap;

public class Similarity {
	
	public static double getPearsonCorrelation(double[] X, double[] Y) {
		double result = 0;
		if (X.length == 0 || Y.length == 0) {
			return result;
		}
		double sigmaX = 0.0;
		double sigmaY = 0.0;
		double sigmaXY = 0.0;
		double sigmaX2 = 0.0;
		double sigmaY2 = 0.0;
		double x = 0, y = 0;
		int length = X.length > Y.length ? X.length : Y.length;

		for (int index = 0; index < length; index++) {
			if (index >= X.length) {
				x = 0;
			} else {
				x = X[index];
			}
			if (index >= Y.length) {
				y = 0;
			} else {
				y = Y[index];
			}
			sigmaX += x;
			sigmaY += y;
			sigmaXY += (x * y);
			sigmaX2 += Math.pow(x, 2);
			sigmaY2 += Math.pow(y, 2);
		}
		double numerator = sigmaXY - ((sigmaX * sigmaY) / length);
		double denominator1 = sigmaX2 - (Math.pow(sigmaX, 2) / length);
		double denominator2 = sigmaY2 - (Math.pow(sigmaY, 2) / length);
		double denominator = Math.sqrt(denominator1 * denominator2);
		
		
//		// System.out.println("sigmaX:"+sigmaX);
//		// System.out.println("sigmaY:"+sigmaY);
//		// System.out.println("sigmaXY:"+sigmaXY);
//		// System.out.println("sigmaX2:"+sigmaX2);
//		// System.out.println("sigmaY2:"+sigmaY2);
//		// System.out.println("numerator:"+numerator);
//		// System.out.println("denominator1:"+denominator1);
//		// System.out.println("denominator2:"+denominator2);
//		// System.out.println("denominator:"+denominator);
		
		if (denominator == 0) {
			result = 0.0;
		} else {
			result = numerator / denominator;
		}

		return result;
	}

	public static double getPearsonCorrelation(HashMap<String, Double> X, HashMap<String, Double> Y) {
		double result = 0;
//		if (X.length == 0 || Y.length == 0) {
//			return result;
//		}
		double sigmaX = 0.0;
		double sigmaY = 0.0;
		double sigmaXY = 0.0;
		double sigmaX2 = 0.0;
		double sigmaY2 = 0.0;
		
		HashMap<String, Double> ab = new HashMap<String, Double>(X);
		ab.putAll(Y);
		
		int length = ab.size();
		
//		// System.out.println("Length : "+length);
		
		for (String key: X.keySet())
		{
			double rating = X.get(key);
			
			sigmaX+=rating;
			sigmaX2+=rating*rating;
		}
		
		for (String key: Y.keySet())
		{
			double rating = Y.get(key);
			
			sigmaY+=rating;
			sigmaY2+=rating*rating ;
		}
		
		for (String key: X.keySet())
		{
			if (Y.get(key)!=null)
			{
				sigmaXY+=X.get(key) * Y.get(key);
			}
		}
		
		double numerator = sigmaXY - ((sigmaX * sigmaY) / length);
		double denominator1 = sigmaX2 - (Math.pow(sigmaX, 2) / length);
		double denominator2 = sigmaY2 - (Math.pow(sigmaY, 2) / length);
		double denominator = Math.sqrt(denominator1 * denominator2);
		
//		// System.out.println("sigmaX:"+sigmaX);
//		// System.out.println("sigmaY:"+sigmaY);
//		// System.out.println("sigmaXY:"+sigmaXY);
//		// System.out.println("sigmaX2:"+sigmaX2);
//		// System.out.println("sigmaY2:"+sigmaY2);
//		// System.out.println("numerator:"+numerator);
//		// System.out.println("denominator1:"+denominator1);
//		// System.out.println("denominator2:"+denominator2);
//		// System.out.println("denominator:"+denominator);
		
		if (denominator == 0) {
			result = 0.0;
		} else {
			result = numerator / denominator;
		}

		return result;
	}
	
	public static double cosineSimilarity(double[] rating1, double[] rating2) {
		double result = 0;
		double dotProduct = dotProduct(rating1, rating2);
		double normRating1 = norm(rating1);
		double normRating2 = norm(rating2);

//		// System.out.println("Dot Product : "+dotProduct);
//		// System.out.println("Norm Rating 1 : "+normRating1);
//		// System.out.println("Norm Rating 2 : "+normRating2);
		if (dotProduct == 0 || normRating1 == 0 || normRating2 == 0)
			;
		else {
			result = dotProduct / (normRating1 * normRating2);
		}
		return result;
	}

	public static double cosineSimilarity(HashMap<String, Double> rating1, HashMap<String, Double> rating2) {
		double result = 0;
		double dotProduct = dotProduct(rating1, rating2);
		double normRating1 = norm(rating1);
		double normRating2 = norm(rating2);

		// System.out.println("******************Rating1************************");
//		for (String key: rating1.keySet())
//		{
			// System.out.println("Key : "+key+"Value : "+rating1.get(key));
//		}
		// System.out.println("************************************************");
		
		// System.out.println("******************Rating2************************");
//		for (String key: rating2.keySet())
//		{
			// System.out.println("Key : "+key+"Value : "+rating2.get(key));
//		}
		// System.out.println("************************************************");
		if (dotProduct == 0 || normRating1 == 0 || normRating2 == 0)
			;
		else {
			result = dotProduct / (normRating1 * normRating2);
		}
		return result;
	}
	private static double dotProduct(double[] x, double[] y) {
		double result = 0.0;

		int length = x.length >= y.length ? y.length : x.length;

		for (int index = 0; index < length; index++) {
			result += x[index] * y[index];
		}
		return result;
	}

	private static double dotProduct(HashMap<String, Double> x, HashMap<String, Double> y) {
		double result = 0.0;

		for (String key: x.keySet())
		{
			if (y.get(key) != null)
			{
				result+=x.get(key)*y.get(key);
			}
		}
		return result;
	}
	
	private static double norm(double[] x) {
		double squareSum = 0.0;
		for (int index = 0; index < x.length; index++) {
			squareSum += x[index] * x[index];
		}
		return Math.sqrt(squareSum);
	}
	
	private static double norm(HashMap<String, Double> x) {
		double squareSum = 0.0;
		for (String key: x.keySet())
		{
			squareSum+=x.get(key)*x.get(key);
		}
		return Math.sqrt(squareSum);
	}

	public static void main(String a[]) {
		double rating1[] = { 1.0, 4.0, 5.0, 7.0, 0.0};
		double rating2[] = { 2.0, 3.0, 5.0, 0.0, 9.0};
		
		HashMap<String, Double> map1 = new HashMap<String, Double>();
		
		HashMap<String, Double> map2 = new HashMap<String, Double>();
		
		map1.put("1", 1.0);
		map1.put("2", 4.0);
		map1.put("3", 5.0);
		map1.put("4", 7.0);
		
		map2.put("1", 2.0);
		map2.put("2", 3.0);
		map2.put("3", 5.0);
		map2.put("5", 9.0);
		
		 System.out.println("**************DOUBLE VALUES**************");
		 System.out.println(cosineSimilarity(rating1, rating2));
		 System.out.println(getPearsonCorrelation(rating1, rating2));
		
		
		 System.out.println("**************MAP VALUES**************");
		 System.out.println(cosineSimilarity(map1, map2));
		 System.out.println(getPearsonCorrelation(map1, map2));
	}

}
